package de.unibi.mmi.homeauto.team1.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

import android.widget.Toast;
import de.unibi.mmi.homeauto.team1.constants.BATH;
import de.unibi.mmi.homeauto.team1.constants.BEDROOM;
import de.unibi.mmi.homeauto.team1.constants.CORRIDOR;
import de.unibi.mmi.homeauto.team1.constants.DeviceValues;
import de.unibi.mmi.homeauto.team1.constants.KITCHEN;
import de.unibi.mmi.homeauto.team1.constants.LIVINGROOM;
import de.unibi.mmi.homeauto.team1.constants.MORE;
import de.unibi.mmi.homeauto.team1.mainview.MainViewActivity;

public class Client implements Runnable {

	private static final int SOCKET_TIMEOUT = 250;

	private static final int SLEEP_TIME = 500;

	private PrintWriter writer;
	private Socket socket;
	private BufferedReader reader;

	private boolean close = false;

	private MainViewActivity mva;

	public Client(final MainViewActivity mva) {
		this.mva = mva;
	}

	public static final float getValue(int id) {
		if (id < 12) {
			return BATH.getValue(id);
		} else if (id < 32) {
			return KITCHEN.getValue(id);
		} else if (id < 48) {
			return BEDROOM.getValue(id);
		} else if (id < 68) {
			return LIVINGROOM.getValue(id);
		} else if (id < 86) {
			return CORRIDOR.getValue(id);
		} else {
			return MORE.getValue(id);
		}
	}

	private void updateValues(int id) {

		// TODO: Hier tatsächlich immer alle Werte nachfragen, die von Relevanz
		// sind.
		this.writer.println("GET " + id);
	}

	public void setValue(int id, float value) {
		this.setValue(id, value, true);
	}

	public void setValue(int id, float value, boolean update) {
		try {
			if (id == KITCHEN.SET_OVEN_TEMP_ID) {
				if (value > 300) {
					value = 300;
				} else if (value < 40) {
					value = 40;
				}
				mva.debug(this, "setValue(): SET " + id + " " + ((int) value));
				this.writer.println("SET " + id + " " +  ((int) value));
				this.updateValues(id);
				if (update) {
					this.writer.println("GET 500");
				}
			} else if (id == BATH.WATER_TEMP_ID) {
				if (value > 60) {
					value = 60;
				} else if (value < 10) {
					value = 10;
				}
				mva.debug(this, "setValue(): SET " + id + " " + value);
				this.writer.println("SET " + id + " " + value);
				this.updateValues(id);
				if (update) {
					this.writer.println("GET 500");
				}
			} else if (id == BATH.SET_ROOM_TEMP_ID
					|| id == KITCHEN.SET_ROOM_TEMP_ID
					|| id == BEDROOM.SET_ROOM_TEMP_ID
					|| id == LIVINGROOM.SET_ROOM_TEMP_ID
					|| id == CORRIDOR.SET_ROOM_TEMP_ID) {
				if (value > 30) {
					value = 30;
				} else if (value < 10) {
					value = 10;
				}
				mva.debug(this, "setValue(): SET " + id + " " + value);
				this.writer.println("SET " + id + " " + value);
				this.updateValues(id);
				if (update) {
					this.writer.println("GET 500");
				}

			} else {
				mva.debug(this, "setValue(): SET " + id + " " + ((int) value));
				this.writer.println("SET " + id + " " + ((int) value));
				this.updateValues(id);

				if (update) {
					this.writer.println("GET 500");
				}
			}
		} catch (Exception e) {
			if (!close) {
				mva.clientError();
			}
		}
	}

	public void close() {
		close = true;
		try {
			this.writer.println("BYE");
		} catch (Exception e) {
			mva.debug(this, "close(): Kann dem Server nicht BYE sagen.");
		}
		try {
			this.writer.close();
		} catch (Exception e) {
			mva.debug(this, "close(): Fehler beim Schließen des Writers.");
		}
		try {
			this.reader.close();
		} catch (Exception e) {
			mva.debug(this, "close(): Fehler beim Schließen des Readers.");
		}
		try {
			this.socket.close();
		} catch (Exception e) {
			mva.debug(this, "close(): Fehler beim Schließen des Sockets.");
		}
	}

	@Override
	public void run() {

		try {
			// Thread.sleep(3000);
			this.socket = new Socket();
			mva.debug(this, "run(): Verbinde zu " + mva.getServerAddress()
					+ ":" + mva.getServerPort() + ".");
			socket.connect(
					new InetSocketAddress(mva.getServerAddress(), mva
							.getServerPort()), Client.SOCKET_TIMEOUT);

			mva.debug(this, "run(): Erstelle PrintWriter.");
			this.writer = new PrintWriter(this.socket.getOutputStream(), true);

			mva.debug(this, "run(): Erstelle BufferedReader.");
			this.reader = new BufferedReader(new InputStreamReader(
					this.socket.getInputStream()));

			mva.debug(this, "run(): Erstelle ClientReader.");
			new Thread(new ClientReader(reader)).start();

			mva.debug(this, "run(): Erstelle GetWriter.");
			new Thread(new GetWriter()).start();

			mva.clientConnected();
			mva.showToast(
					"Verbindung hergestellt zu\n" + mva.getServerAddress()
							+ ":" + mva.getServerPort() + ".",
					Toast.LENGTH_LONG);

		} catch (Exception e) {
			if (!close) {
				mva.clientError();
			}
		}
	}

	int i = 0;

	private class GetWriter implements Runnable {

		@Override
		public void run() {
			try {
				while (true) {
					if (i++ == 5) {
						i = 0;
						if (Client.getValue(KITCHEN.SET_ROOM_TEMP_ID) != Client
								.getValue(KITCHEN.CURRENT_ROOM_TEMP_ID)) {
							writer.println("SET " + KITCHEN.HEATING_ID + " "
									+ DeviceValues.HEATING_ON);
						} else {
							writer.println("SET " + KITCHEN.HEATING_ID + " "
									+ DeviceValues.HEATING_OFF);
						}
						if (Client.getValue(BATH.SET_ROOM_TEMP_ID) != Client
								.getValue(BATH.CURRENT_ROOM_TEMP_ID)) {
							writer.println("SET " + BATH.HEATING_ID + " "
									+ DeviceValues.HEATING_ON);
						} else {
							writer.println("SET " + BATH.HEATING_ID + " "
									+ DeviceValues.HEATING_OFF);
						}
						if (Client.getValue(LIVINGROOM.SET_ROOM_TEMP_ID) != Client
								.getValue(LIVINGROOM.CURRENT_ROOM_TEMP_ID)) {
							writer.println("SET " + LIVINGROOM.HEATING_ID + " "
									+ DeviceValues.HEATING_ON);
						} else {
							writer.println("SET " + LIVINGROOM.HEATING_ID + " "
									+ DeviceValues.HEATING_OFF);
						}
						if (Client.getValue(BEDROOM.SET_ROOM_TEMP_ID) != Client
								.getValue(BEDROOM.CURRENT_ROOM_TEMP_ID)) {
							writer.println("SET " + BEDROOM.HEATING_ID + " "
									+ DeviceValues.HEATING_ON);
						} else {
							writer.println("SET " + BEDROOM.HEATING_ID + " "
									+ DeviceValues.HEATING_OFF);
						}
						if (Client.getValue(CORRIDOR.SET_ROOM_TEMP_ID) != Client
								.getValue(CORRIDOR.CURRENT_ROOM_TEMP_ID)) {
							writer.println("SET " + CORRIDOR.HEATING_ID + " "
									+ DeviceValues.HEATING_ON);
						} else {
							writer.println("SET " + CORRIDOR.HEATING_ID + " "
									+ DeviceValues.HEATING_OFF);
						}
					}
					for (int currentID : BATH.IDS) {
						writer.println("GET " + currentID);
					}
					for (int currentID : BEDROOM.IDS) {
						writer.println("GET " + currentID);
					}
					for (int currentID : CORRIDOR.IDS) {
						writer.println("GET " + currentID);
					}
					for (int currentID : KITCHEN.IDS) {
						writer.println("GET " + currentID);
					}
					for (int currentID : LIVINGROOM.IDS) {
						writer.println("GET " + currentID);
					}
					for (int currentID : MORE.IDS) {
						writer.println("GET " + currentID);
					}
					Thread.sleep(SLEEP_TIME);
				}
			} catch (Exception e) {
				if (!close) {
					mva.clientError();
				}
			}
			if (!close) {
				mva.clientError();
			}
		}
	}

	private class ClientReader implements Runnable {

		private BufferedReader bufferedReader;

		private ClientReader(BufferedReader buffReader) {
			this.bufferedReader = buffReader;
		}

		@Override
		public void run() {
			String inputLine;
			mva.debug(this, "run(): Beginne Werte vom Server zu lesen.");

			try {
				while ((inputLine = bufferedReader.readLine()) != null) {
					if (inputLine.startsWith("STATUS")) {
						String[] idValue = inputLine.split(" ");
						int id = Integer.parseInt(idValue[1]);
						float value = -1;
						if (inputLine.contains(".")) {
							value = Float.parseFloat(idValue[2]);
						} else {
							value = Integer.parseInt(idValue[2]);
						}
						if (id < 12) {
							BATH.setValue(id, value);
						} else if (id < 32) {
							KITCHEN.setValue(id, value);
						} else if (id < 48) {
							BEDROOM.setValue(id, value);
						} else if (id < 68) {
							LIVINGROOM.setValue(id, value);
						} else if (id < 86) {
							CORRIDOR.setValue(id, value);
						} else {
							MORE.setValue(id, value);
						}

						if (id == 500 && mva != null) {
							mva.serverValuesUpdated();
						}
					}
				}

			} catch (Exception e) {
				mva.debug(this, "run(): " + e.getMessage());
				if (!close) {
					mva.clientError();
				}
			}
			if (!close) {
				mva.clientError();
			}
		}
	}
}
